package srzy.diameter

import srzy.common._

object DataFormat {

  val dict = xml.XML loadString readFromFile("etc/dict.xml").mkString("\n")

  val types = Map("Integer32" -> "Int",
    "Unsigned32" -> "Int",
    "Integer64" -> "Long",
    "Unsigned64" -> "Long",
    "OctetString" -> "String",
    "Grouped" -> "Grouped",
    "Time" -> "UnsignedInt",
    "Address" -> "String",
    "TimeStamp" -> "Int",
    "Enumerated" -> "Int",
    "UTF8String" -> "UTF8String")
  val dccHeaderName = (dict \ "header" \\ "@name").head.text // command
  val dccHeaderLengthText = (dict \ "header" \\ "@length").head.text // msg-length
  val dccHeaderType = (dict \ "header" \\ "@type").head.text // cmd-code
  val dccHeaderFields = (dict \ "header" \ "fielddef").toList
    .map(x => ((x \\ "@name").head.text, (x \\ "@size").head.text.toInt))
  val dccHeaderDict = (dict \ "dictionary" \ dccHeaderName \ "define").toList
    .map(node => {
      ((node \\ "@name").head.text,
        (node \ "setfield").toList.map(x => ((x \\ "@name").head.text, (x \\ "@value").head.text)))
    })

  val dccHeaderLength = dccHeaderFields.map(_._2.toInt).reduceLeft(_ + _)
  val dccHeaderFieldsInfo = dccHeaderFields
    .map(x => (x._1, x._2.toInt)).scanLeft(("", (0, 0)))((a, b) => {
      (b._1, (if (a._1 == "") 0 else a._2._1 + a._2._2, b._2))
    }).tail
  val dccHeaderFieldsInfoMap = dccHeaderFieldsInfo.toMap

  /*
   * 
   */

  val avpHeaderName = (dict \ "body" \ "header" \\ "@name").head.text // avp
  val avpHeaderLengthText = (dict \ "body" \ "header" \\ "@length").head.text // avp-length
  val avpHeaderType = (dict \ "body" \ "header" \\ "@type").head.text // avp-code
  val avpHeaderFields = (dict \ "body" \ "header").head
    .child.toList.filter(t => t.label == "fielddef")
    .map(t => ((t \\ "@name").head.text, (t \\ "@size").head.text))
  val optionalAVPHeaderFields = (dict \ "body" \ "header" \ "optional").head
    .child.toList.filter(t => t.label == "fielddef")
    .map(t => ((t \\ "@name").head.text,
      (t \\ "@size").head.text,
      (t \\ "@condition").head.text,
      (t \\ "@field").head.text,
      (t \\ "@mask").head.text))

  val avpDict = (dict \ "dictionary" \ avpHeaderName \ "define").toList
    .foldLeft(List.empty[(String, String, String, List[(String, String)])])(
      (l, node) => {
        val name = node.attributes.apply("name").head.text
        val dataType = node.attributes.apply("type").head.text
        val dateType2 = types.apply(dataType)
        val fields = (node \\ "setfield").toList
          .map(x => ((x \\ "@name").head.text, (x \\ "@value").head.text))

        val avpCode = fields.toMap.apply(avpHeaderType)

        val e = (name, avpCode, dateType2, fields)
        if (l.exists(t => e._1 == t._1 ||
          e._2 == t._2)) {
          //            println(e)
          //            println(node)
          l
        } else {
          l ::: e :: Nil
        }
      })

  val option = optionalAVPHeaderFields.head

  val noOptionAVPHeaderFields = avpHeaderFields
  val noOptionAVPHeaderLength = avpHeaderFields.map(_._2.toInt).reduceLeft(_ + _)
  val noOptionAVPHeaderFieldsInfo = noOptionAVPHeaderFields
    .map(x => (x._1, x._2.toInt)).scanLeft(("", (0, 0)))((a, b) => {
      (b._1, (if (a._1 == "") 0 else a._2._1 + a._2._2, b._2))
    }).tail
  val noOptionAVPHeaderFieldsInfoMap = noOptionAVPHeaderFieldsInfo.toMap

  val withOptionAVPHeaderFields = (DataFormat.avpHeaderFields ++
    optionalAVPHeaderFields.map(x => (x._1, x._2)) ++ Nil)
  val withOptionAVPHeaderLength = withOptionAVPHeaderFields.map(_._2.toInt).reduceLeft(_ + _)
  val withOptionAVPHeaderFieldsInfo = withOptionAVPHeaderFields
    .map(x => (x._1, x._2.toInt)).scanLeft(("", (0, 0)))((a, b) => {
      (b._1, (if (a._1 == "") 0 else a._2._1 + a._2._2, b._2))
    }).tail
  val withOptionAVPHeaderFieldsInfoMap = withOptionAVPHeaderFieldsInfo.toMap

  //  println("types:" + types)
  //  println("dccHeaderName:" + dccHeaderName)
  //  println("dccHeaderLengthText:" + dccHeaderLengthText)
  //  println("dccHeaderType:" + dccHeaderType)
  //  println("dccHeaderFields:" + dccHeaderFields)
  //  println("dccHeaderDict:" + dccHeaderDict)
  //  println("dccHeaderLength:" + dccHeaderLength)
  //  println("dccHeaderFieldsInfo:" + dccHeaderFieldsInfo)
  //  println("dccHeaderFieldsInfoMap:" + dccHeaderFieldsInfoMap)
  //
  //  println("avpHeaderName:" + avpHeaderName)
  //  println("avpHeaderLengthText:" + avpHeaderLengthText)
  //  println("avpHeaderType:" + avpHeaderType)
  //  println("avpHeaderFields:" + avpHeaderFields)
  //  println("optionalAVPHeaderFields:" + optionalAVPHeaderFields)
  //  println("avpDict:" + avpDict)
  //  println("option:" + option)
  //  println("noOptionAVPHeaderFields:" + noOptionAVPHeaderFields)
  //  println("noOptionAVPHeaderLength:" + noOptionAVPHeaderLength)
  //  println("noOptionAVPHeaderFieldsInfo:" + noOptionAVPHeaderFieldsInfo)
  //  println("noOptionAVPHeaderFieldsInfoMap:" + noOptionAVPHeaderFieldsInfoMap)
  //  println("withOptionAVPHeaderFields:" + withOptionAVPHeaderFields)
  //  println("withOptionAVPHeaderLength:" + withOptionAVPHeaderLength)
  //  println("withOptionAVPHeaderFieldsInfo:" + withOptionAVPHeaderFieldsInfo)
  //  println("withOptionAVPHeaderFieldsInfoMap:" + withOptionAVPHeaderFieldsInfoMap)

}